﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.IO;
using System.Web.Caching;

namespace JQuery.Net.Controls
{
    [ToolboxData("<{0}:CSSProcessor runat=server />")]
    public sealed class CSSProcessor 
        : Control
        , ICSSProcessor
    {
        #region constructor
        public CSSProcessor()
            : base()
        {
            EnableViewState = false;
            EnableTheming = false;

            if (Config.CSSThemeOverride)
            {   // with theme override enabled we can expect the theme.css file to exist in the css folder
                CSSFolder = Config.CssFolder;
            }
        }
        #endregion

        #region properties
        [Browsable(true), Bindable(false), Category("Behavior"), DisplayName("Image Resource Folder")]
        public string CSSFolder { get; set; }
        /// <summary>
        /// Get a reference to the current state of the reference manager.
        /// </summary>
        [
        Browsable(false),
        Bindable(false)
        ]
        public List<Resource.Content> Resources { get { return Page.ResourceIncludes().ResourceList(Resource.ContentTypes.css); } }
        /// <summary>
        /// Get a reference to the resource manager
        /// </summary>
        [
        Browsable(false),
        Bindable(false)
        ]
        public Resource Manager { get { return Module.Manager; } }

        private string Path { get; set; }
        #endregion

        protected override void OnInit(EventArgs e)
        {
            base.OnInit(e);

            if(Page.Theme.IsNotNullOrEmpty() && !Config.CSSThemeOverride)
            {   // progmatically the app_theme can be changed on page pre-init
                CSSFolder = String.Format("~/app_themes/{0}", Page.Theme.ToLower());
            }

            Page.PreRenderComplete += new EventHandler(Page_PreRenderComplete);
        }

        void Page_PreRenderComplete(object sender, EventArgs e)
        {   /// at this point all the css that is going to be registered should be registered
            /// merge all files into one and cache it.
            if (Config.IsOptimized)
            {
                string
                    the_css_path = Page.Server.MapPath(Page.ResolveUrl(Manager.GeneratedCssPath)),
                    file_path = Page.Request.FilePath,
                    file_name = file_path.Substring(file_path.LastIndexOf("/") + 1).Replace(".aspx", "").ToLower(),
                    cache_key = Manager.GetResourceKey(file_name, Resource.ContentTypes.css);

                if (!Convert.ToBoolean(Manager.Cache[cache_key]) && Resources.Count > 0)
                {
                    if (!Manager.GeneratedCssPathExists)
                    {
                        Directory.CreateDirectory(the_css_path);
                    }

                    using (StreamWriter oWriter = new StreamWriter(File.Open(String.Format("{0}\\{1}.css", the_css_path, file_name), FileMode.Create)))
                    {
                        foreach (var Res in Resources)
                        {
                            Res.Body(oWriter);
                        }

                        oWriter.Flush();
                    }
                    Manager.Add(file_name, String.Format("{0}/{1}.css", Manager.GeneratedCssPath, file_name), Resource.ContentTypes.css);
                    // we have generated a file and to prevent this file from being regenerated for every request we are going to set a flag in cache
                    Manager.Cache.Add(cache_key, true, new CacheDependency(Page.Server.MapPath(Page.Request.Url.AbsolutePath)),
                        Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.AboveNormal, null);
                }
                // remove all include files for css and replace them with the merged file
                Page.ResourceIncludes().Clear(Resource.ContentTypes.css);
                // register the optimized file
                Page.RegisterResourceInclude(file_name, Resource.ContentTypes.css);
            }
        }

        protected override void Render(HtmlTextWriter writer)
        {
            writer.Indent++;

            foreach (Resource.Content css in Resources.OrderBy(x => x.uri))
            {
                writer.WriteLine();
                writer.AddAttribute(HtmlTextWriterAttribute.Type, Resource.ContentTypes.css);
                writer.AddAttribute(HtmlTextWriterAttribute.Rel, "stylesheet");
                writer.AddAttribute(HtmlTextWriterAttribute.Href, String.Format("{0}/{1}.CSS", Page.ResolveUrl(CSSFolder), css.id));
                writer.RenderBeginTag(HtmlTextWriterTag.Link);
                writer.RenderEndTag();
            }

            writer.Indent--;
        }
    }
}
